Enter the directory of the maca folder on your drive and the name of the tissue you want to analyze.

tissue_of_interest = "Bladder"
library(here)
source(here("00_data_ingest", "02_tissue_analysis_rmd", "boilerplate.R"))
tiss = load_tissue_facs(tissue_of_interest)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
[1] "Scaling data matrix"

  |                                                                                       
  |                                                                                 |   0%
  |                                                                                       
  |=================================================================================| 100%
Calculating gene means
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variance to mean ratios
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|

Visualize top genes in principal components

Later on (in FindClusters and TSNE) you will pick a number of principal components to use. This has the effect of keeping the major directions of variation in the data and, ideally, supressing noise. There is no correct answer to the number to use, but a decent rule of thumb is to go until the plot plateaus.

PCElbowPlot(object = tiss)

Choose the number of principal components to use.

# Set number of principal components. 
n.pcs = 10

The clustering is performed based on a nearest neighbors graph. Cells that have similar expression will be joined together. The Louvain algorithm looks for groups of cells with high modularity–more connections within the group than between groups. The resolution parameter determines the scale…higher resolution will give more clusters, lower resolution will give fewer.

For the top-level clustering, aim to under-cluster instead of over-cluster. It will be easy to subset groups and further analyze them below.

# Set resolution 
res.used <- 0.4
tiss <- FindClusters(object = tiss, reduction.type = "pca", dims.use = 1:n.pcs, 
    resolution = res.used, print.output = 0, save.SNN = TRUE, force.recalc=TRUE)

To visualize

# If cells are too spread out, you can raise the perplexity. If you have few cells, try a lower perplexity (but never less than 10).
tiss <- RunTSNE(object = tiss, dims.use = 1:n.pcs, seed.use = 10, perplexity=30)
###############Figure1 
##note that you can set do.label=T to help label individual clusters
TSNEPlot(object = tiss, do.label = T)

Compare to previous annotations

filename = here('00_data_ingest', '03_tissue_annotation_csv', 
                     paste0(tissue_of_interest, "_facs_annotation.csv.backup"))
previous_annotation = read_csv(filename)
Missing column names filled in: 'X1' [1]Parsed with column specification:
cols(
  X1 = col_character(),
  plate.barcode = col_character(),
  cell_ontology_class = col_character(),
  free_annotation = col_character(),
  cell_ontology_id = col_character()
)
tiss@meta.data[, 'previous_cell_ontology_class'] <- "NA"
tiss@meta.data[as.character(previous_annotation$X1), 'previous_cell_ontology_class'] <- as.character(previous_annotation$cell_ontology_class)
TSNEPlot(object = tiss, do.return = TRUE, group.by = "previous_cell_ontology_class")

tiss@meta.data[, 'previous_free_annotation'] <- "NA"
tiss@meta.data[as.character(previous_annotation$X1), 'previous_free_annotation'] <- as.character(previous_annotation$free_annotation)
TSNEPlot(object = tiss, do.return = TRUE, group.by = "previous_free_annotation")

table(tiss@meta.data[, "previous_cell_ontology_class"])

           bladder cell bladder urothelial cell                      NA 
                    671                     616                      91 
table(tiss@meta.data[, "previous_cell_ontology_class"], tiss@ident)
                         
                            0   1   2   3   4   5   6
  bladder cell            331   0 253   0   0  76  11
  bladder urothelial cell   0 287   0 141 100   0  88
  NA                        7   2   1  48   4  27   2
table(tiss@meta.data[, "previous_free_annotation"], tiss@ident)
                                 
                                    0   1   2   3   4   5   6
  Basal bladder epithelial cell     0  60   0   0   0   0  88
  Bladder mesenchymal cell        331   0 253   0   0  76  11
  Luminal bladder epithelial cell   0 227   0 141 100   0   0
  NA                                7   2   1  48   4  27   2

Check expression of genes of interset.

Dotplots let you see the intensity of exppression and the fraction of cells expressing for each of your genes of interest.

###############Figure2
VlnPlot(tiss, genes_to_check)

BuildClusterTree(tiss)
[1] "Finished averaging RNA for cluster 0"
[1] "Finished averaging RNA for cluster 1"
[1] "Finished averaging RNA for cluster 2"
[1] "Finished averaging RNA for cluster 3"
[1] "Finished averaging RNA for cluster 4"
[1] "Finished averaging RNA for cluster 5"
[1] "Finished averaging RNA for cluster 6"
An object of class seurat in project Bladder 
 23341 genes across 1378 samples.

Check expression of genes of interset.

How big are the clusters?

table(tiss@ident)

  0   1   2   3   4   5   6 
338 289 254 189 104 103 101 

Which markers identify a specific cluster?

clust.markers <- FindMarkers(object = tiss, ident.1 = 0, only.pos = TRUE, min.pct = 0.25, thresh.use = 0.25)

   |                                                  | 0 % ~calculating  
   |+                                                 | 1 % ~01m 24s      
   |+                                                 | 2 % ~01m 31s      
   |++                                                | 3 % ~01m 28s      
   |++                                                | 4 % ~01m 26s      
   |+++                                               | 5 % ~01m 25s      
   |+++                                               | 6 % ~01m 24s      
   |++++                                              | 7 % ~01m 23s      
   |++++                                              | 8 % ~01m 21s      
   |+++++                                             | 9 % ~01m 20s      
   |+++++                                             | 10% ~01m 19s      
   |++++++                                            | 11% ~01m 18s      
   |++++++                                            | 12% ~01m 17s      
   |+++++++                                           | 13% ~01m 16s      
   |+++++++                                           | 14% ~01m 15s      
   |++++++++                                          | 15% ~01m 14s      
   |++++++++                                          | 16% ~01m 13s      
   |+++++++++                                         | 17% ~01m 12s      
   |+++++++++                                         | 18% ~01m 11s      
   |++++++++++                                        | 19% ~01m 10s      
   |++++++++++                                        | 20% ~01m 09s      
   |+++++++++++                                       | 21% ~01m 08s      
   |+++++++++++                                       | 22% ~01m 08s      
   |++++++++++++                                      | 23% ~01m 07s      
   |++++++++++++                                      | 24% ~01m 06s      
   |+++++++++++++                                     | 25% ~01m 06s      
   |+++++++++++++                                     | 26% ~01m 05s      
   |++++++++++++++                                    | 27% ~01m 04s      
   |++++++++++++++                                    | 28% ~01m 03s      
   |+++++++++++++++                                   | 29% ~01m 02s      
   |+++++++++++++++                                   | 30% ~01m 01s      
   |++++++++++++++++                                  | 31% ~01m 00s      
   |++++++++++++++++                                  | 32% ~59s          
   |+++++++++++++++++                                 | 33% ~58s          
   |+++++++++++++++++                                | 34% ~57s          
   |++++++++++++++++++                                | 35% ~57s          
   |++++++++++++++++++                                | 36% ~56s          
   |+++++++++++++++++++                               | 37% ~55s          
   |+++++++++++++++++++                               | 38% ~54s          
   |++++++++++++++++++++                              | 39% ~53s          
   |++++++++++++++++++++                              | 40% ~52s          
   |+++++++++++++++++++++                             | 41% ~51s          
   |+++++++++++++++++++++                             | 42% ~50s          
   |++++++++++++++++++++++                            | 43% ~50s          
   |++++++++++++++++++++++                            | 44% ~49s          
   |+++++++++++++++++++++++                           | 45% ~48s          
   |+++++++++++++++++++++++                           | 46% ~47s          
   |++++++++++++++++++++++++                          | 47% ~46s          
   |++++++++++++++++++++++++                          | 48% ~45s          
   |+++++++++++++++++++++++++                         | 49% ~44s          
   |+++++++++++++++++++++++++                         | 50% ~43s          
   |++++++++++++++++++++++++++                        | 51% ~42s          
   |++++++++++++++++++++++++++                        | 52% ~42s          
   |+++++++++++++++++++++++++++                       | 53% ~41s          
   |+++++++++++++++++++++++++++                       | 54% ~40s          
   |++++++++++++++++++++++++++++                      | 55% ~39s          
   |++++++++++++++++++++++++++++                     | 56% ~38s          
   |+++++++++++++++++++++++++++++                     | 57% ~37s          
   |+++++++++++++++++++++++++++++                     | 58% ~36s          
   |++++++++++++++++++++++++++++++                    | 59% ~36s          
   |++++++++++++++++++++++++++++++                    | 60% ~35s          
   |+++++++++++++++++++++++++++++++                   | 61% ~34s          
   |+++++++++++++++++++++++++++++++                   | 62% ~33s          
   |++++++++++++++++++++++++++++++++                  | 63% ~32s          
   |++++++++++++++++++++++++++++++++                  | 64% ~31s          
   |+++++++++++++++++++++++++++++++++                 | 65% ~30s          
   |+++++++++++++++++++++++++++++++++                 | 66% ~29s          
   |++++++++++++++++++++++++++++++++++                | 67% ~29s          
   |++++++++++++++++++++++++++++++++++               | 68% ~28s          
   |+++++++++++++++++++++++++++++++++++               | 69% ~27s          
   |+++++++++++++++++++++++++++++++++++               | 70% ~26s          
   |++++++++++++++++++++++++++++++++++++              | 71% ~25s          
   |++++++++++++++++++++++++++++++++++++              | 72% ~24s          
   |+++++++++++++++++++++++++++++++++++++             | 73% ~23s          
   |+++++++++++++++++++++++++++++++++++++             | 74% ~22s          
   |++++++++++++++++++++++++++++++++++++++            | 75% ~22s          
   |++++++++++++++++++++++++++++++++++++++            | 76% ~21s          
   |+++++++++++++++++++++++++++++++++++++++           | 77% ~20s          
   |+++++++++++++++++++++++++++++++++++++++          | 78% ~19s          
   |++++++++++++++++++++++++++++++++++++++++          | 79% ~18s          
   |++++++++++++++++++++++++++++++++++++++++         | 80% ~17s          
   |+++++++++++++++++++++++++++++++++++++++++         | 81% ~16s          
   |+++++++++++++++++++++++++++++++++++++++++         | 82% ~16s          
   |++++++++++++++++++++++++++++++++++++++++++        | 83% ~15s          
print(x = head(x= clust.markers, n = 10))

You can also compute all markers for all clusters at once. This may take some time.

tiss.markers <- FindAllMarkers(object = tiss, only.pos = TRUE, min.pct = 0.25, thresh.use = 0.25)

   |                                                  | 0 % ~calculating  
   |+                                                 | 1 % ~03m 55s      
   |++                                                | 2 % ~03m 48s      
   |++                                                | 3 % ~03m 44s      
   |+++                                               | 4 % ~03m 44s      
   |+++                                               | 5 % ~03m 41s      
   |++++                                              | 6 % ~03m 38s      
   |++++                                              | 7 % ~03m 37s      
   |+++++                                             | 8 % ~03m 36s      
   |+++++                                             | 9 % ~03m 33s      
   |++++++                                            | 10% ~03m 29s      
   |++++++                                            | 11% ~03m 27s      
   |+++++++                                           | 12% ~03m 25s      
   |+++++++                                           | 13% ~03m 22s      
   |++++++++                                          | 14% ~03m 21s      
   |++++++++                                          | 15% ~03m 18s      
   |+++++++++                                         | 16% ~03m 15s      
   |+++++++++                                         | 17% ~03m 14s      
   |++++++++++                                        | 18% ~03m 12s      
   |++++++++++                                        | 19% ~03m 09s      
   |+++++++++++                                       | 20% ~03m 07s      

Display the top markers you computed above.

Assigning cell type identity to clusters

At a coarse level, we can use canonical markers to match the unbiased clustering to known cell types:

Checking for batch effects

Color by metadata, like plate barcode, to check for batch effects.

Print a table showing the count of cells in each identity category from each plate.

Save the Robject for later

When you save the annotated tissue, please give it a name.

Export the final metadata

So that Biohub can easily combine all your cell_ontology_classs, please export them as a simple csv.

Checking for batch effects

Color by metadata, like plate barcode, to check for batch effects.

Print a table showing the count of cells in each identity category from each plate.

Save the Robject for later

When you save the annotated tissue, please give it a name.

Export the final metadata

So that Biohub can easily combine all your cell_ontology_classs, please export them as a simple csv.

LS0tCnRpdGxlOiAiQmxhZGRlciBGQUNTIE5vdGVib29rIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpFbnRlciB0aGUgZGlyZWN0b3J5IG9mIHRoZSBtYWNhIGZvbGRlciBvbiB5b3VyIGRyaXZlIGFuZCB0aGUgbmFtZSBvZiB0aGUgdGlzc3VlIHlvdSB3YW50IHRvIGFuYWx5emUuCgpgYGB7cn0KdGlzc3VlX29mX2ludGVyZXN0ID0gIkJsYWRkZXIiCmxpYnJhcnkoaGVyZSkKc291cmNlKGhlcmUoIjAwX2RhdGFfaW5nZXN0IiwgIjAyX3Rpc3N1ZV9hbmFseXNpc19ybWQiLCAiYm9pbGVycGxhdGUuUiIpKQp0aXNzID0gbG9hZF90aXNzdWVfZmFjcyh0aXNzdWVfb2ZfaW50ZXJlc3QpCmBgYAoKVmlzdWFsaXplIHRvcCBnZW5lcyBpbiBwcmluY2lwYWwgY29tcG9uZW50cwoKYGBge3IsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9ClBDSGVhdG1hcChvYmplY3QgPSB0aXNzLCBwYy51c2UgPSAxOjEwLCBjZWxscy51c2UgPSA1MDAsIGRvLmJhbGFuY2VkID0gVFJVRSwgbGFiZWwuY29sdW1ucyA9IEZBTFNFLCBudW0uZ2VuZXMgPSA4KQpgYGAKCkxhdGVyIG9uIChpbiBGaW5kQ2x1c3RlcnMgYW5kIFRTTkUpIHlvdSB3aWxsIHBpY2sgYSBudW1iZXIgb2YgcHJpbmNpcGFsIGNvbXBvbmVudHMgdG8gdXNlLiBUaGlzIGhhcyB0aGUgZWZmZWN0IG9mIGtlZXBpbmcgdGhlIG1ham9yIGRpcmVjdGlvbnMgb2YgdmFyaWF0aW9uIGluIHRoZSBkYXRhIGFuZCwgaWRlYWxseSwgc3VwcmVzc2luZyBub2lzZS4gVGhlcmUgaXMgbm8gY29ycmVjdCBhbnN3ZXIgdG8gdGhlIG51bWJlciB0byB1c2UsIGJ1dCBhIGRlY2VudCBydWxlIG9mIHRodW1iIGlzIHRvIGdvIHVudGlsIHRoZSBwbG90IHBsYXRlYXVzLgoKYGBge3J9ClBDRWxib3dQbG90KG9iamVjdCA9IHRpc3MpCmBgYAoKQ2hvb3NlIHRoZSBudW1iZXIgb2YgcHJpbmNpcGFsIGNvbXBvbmVudHMgdG8gdXNlLgpgYGB7cn0KIyBTZXQgbnVtYmVyIG9mIHByaW5jaXBhbCBjb21wb25lbnRzLiAKbi5wY3MgPSAxMApgYGAKCgpUaGUgY2x1c3RlcmluZyBpcyBwZXJmb3JtZWQgYmFzZWQgb24gYSBuZWFyZXN0IG5laWdoYm9ycyBncmFwaC4gQ2VsbHMgdGhhdCBoYXZlIHNpbWlsYXIgZXhwcmVzc2lvbiB3aWxsIGJlIGpvaW5lZCB0b2dldGhlci4gVGhlIExvdXZhaW4gYWxnb3JpdGhtIGxvb2tzIGZvciBncm91cHMgb2YgY2VsbHMgd2l0aCBoaWdoIG1vZHVsYXJpdHktLW1vcmUgY29ubmVjdGlvbnMgd2l0aGluIHRoZSBncm91cCB0aGFuIGJldHdlZW4gZ3JvdXBzLiBUaGUgcmVzb2x1dGlvbiBwYXJhbWV0ZXIgZGV0ZXJtaW5lcyB0aGUgc2NhbGUuLi5oaWdoZXIgcmVzb2x1dGlvbiB3aWxsIGdpdmUgbW9yZSBjbHVzdGVycywgbG93ZXIgcmVzb2x1dGlvbiB3aWxsIGdpdmUgZmV3ZXIuCgpGb3IgdGhlIHRvcC1sZXZlbCBjbHVzdGVyaW5nLCBhaW0gdG8gdW5kZXItY2x1c3RlciBpbnN0ZWFkIG9mIG92ZXItY2x1c3Rlci4gSXQgd2lsbCBiZSBlYXN5IHRvIHN1YnNldCBncm91cHMgYW5kIGZ1cnRoZXIgYW5hbHl6ZSB0aGVtIGJlbG93LgoKYGBge3J9CiMgU2V0IHJlc29sdXRpb24gCnJlcy51c2VkIDwtIDAuNAoKdGlzcyA8LSBGaW5kQ2x1c3RlcnMob2JqZWN0ID0gdGlzcywgcmVkdWN0aW9uLnR5cGUgPSAicGNhIiwgZGltcy51c2UgPSAxOm4ucGNzLCAKICAgIHJlc29sdXRpb24gPSByZXMudXNlZCwgcHJpbnQub3V0cHV0ID0gMCwgc2F2ZS5TTk4gPSBUUlVFLCBmb3JjZS5yZWNhbGM9VFJVRSkKYGBgCgpUbyB2aXN1YWxpemUgCmBgYHtyfQojIElmIGNlbGxzIGFyZSB0b28gc3ByZWFkIG91dCwgeW91IGNhbiByYWlzZSB0aGUgcGVycGxleGl0eS4gSWYgeW91IGhhdmUgZmV3IGNlbGxzLCB0cnkgYSBsb3dlciBwZXJwbGV4aXR5IChidXQgbmV2ZXIgbGVzcyB0aGFuIDEwKS4KdGlzcyA8LSBSdW5UU05FKG9iamVjdCA9IHRpc3MsIGRpbXMudXNlID0gMTpuLnBjcywgc2VlZC51c2UgPSAxMCwgcGVycGxleGl0eT0zMCkKYGBgCgpgYGB7cn0KIyMjIyMjIyMjIyMjIyMjRmlndXJlMSAKIyNub3RlIHRoYXQgeW91IGNhbiBzZXQgZG8ubGFiZWw9VCB0byBoZWxwIGxhYmVsIGluZGl2aWR1YWwgY2x1c3RlcnMKVFNORVBsb3Qob2JqZWN0ID0gdGlzcywgZG8ubGFiZWwgPSBUKQpgYGAKCgoKQ29tcGFyZSB0byBwcmV2aW91cyBhbm5vdGF0aW9ucwpgYGB7cn0KZmlsZW5hbWUgPSBoZXJlKCcwMF9kYXRhX2luZ2VzdCcsICcwM190aXNzdWVfYW5ub3RhdGlvbl9jc3YnLCAKICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKHRpc3N1ZV9vZl9pbnRlcmVzdCwgIl9mYWNzX2Fubm90YXRpb24uY3N2LmJhY2t1cCIpKQpwcmV2aW91c19hbm5vdGF0aW9uID0gcmVhZF9jc3YoZmlsZW5hbWUpCnRpc3NAbWV0YS5kYXRhWywgJ3ByZXZpb3VzX2NlbGxfb250b2xvZ3lfY2xhc3MnXSA8LSAiTkEiCnRpc3NAbWV0YS5kYXRhW2FzLmNoYXJhY3RlcihwcmV2aW91c19hbm5vdGF0aW9uJFgxKSwgJ3ByZXZpb3VzX2NlbGxfb250b2xvZ3lfY2xhc3MnXSA8LSBhcy5jaGFyYWN0ZXIocHJldmlvdXNfYW5ub3RhdGlvbiRjZWxsX29udG9sb2d5X2NsYXNzKQpUU05FUGxvdChvYmplY3QgPSB0aXNzLCBkby5yZXR1cm4gPSBUUlVFLCBncm91cC5ieSA9ICJwcmV2aW91c19jZWxsX29udG9sb2d5X2NsYXNzIikKCnRpc3NAbWV0YS5kYXRhWywgJ3ByZXZpb3VzX2ZyZWVfYW5ub3RhdGlvbiddIDwtICJOQSIKdGlzc0BtZXRhLmRhdGFbYXMuY2hhcmFjdGVyKHByZXZpb3VzX2Fubm90YXRpb24kWDEpLCAncHJldmlvdXNfZnJlZV9hbm5vdGF0aW9uJ10gPC0gYXMuY2hhcmFjdGVyKHByZXZpb3VzX2Fubm90YXRpb24kZnJlZV9hbm5vdGF0aW9uKQpUU05FUGxvdChvYmplY3QgPSB0aXNzLCBkby5yZXR1cm4gPSBUUlVFLCBncm91cC5ieSA9ICJwcmV2aW91c19mcmVlX2Fubm90YXRpb24iKQpgYGAKCgpgYGB7cn0KdGFibGUodGlzc0BtZXRhLmRhdGFbLCAicHJldmlvdXNfY2VsbF9vbnRvbG9neV9jbGFzcyJdKQpgYGAKCgpgYGB7cn0KdGFibGUodGlzc0BtZXRhLmRhdGFbLCAicHJldmlvdXNfY2VsbF9vbnRvbG9neV9jbGFzcyJdLCB0aXNzQGlkZW50KQpgYGAKCmBgYHtyfQp0YWJsZSh0aXNzQG1ldGEuZGF0YVssICJwcmV2aW91c19mcmVlX2Fubm90YXRpb24iXSwgdGlzc0BpZGVudCkKYGBgCgpDaGVjayBleHByZXNzaW9uIG9mIGdlbmVzIG9mIGludGVyc2V0LgoKYGBge3IsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD04fQpnZW5lc190b19jaGVjayA9IGMoJ0VwY2FtJywnVXBrMWInLCAnVXBrM2EnLCdHcmhsMycsICdLcnQ1JywgJ0tydDE0JywgJ0NkNDQnLCAnRGNuJywgIkNhcjMiLCAiU2NhcmE1IikKI2dlbmVzX3RvX2NoZWNrID0gYygnQWxiJywgJ0N5cDJmMicsICdDeXAyZTEnLCAnSGFtcCcpCgpGZWF0dXJlUGxvdCh0aXNzLCBnZW5lc190b19jaGVjaywgcHQuc2l6ZSA9IDEsIG5Db2wgPSAzKQpgYGAKCkRvdHBsb3RzIGxldCB5b3Ugc2VlIHRoZSBpbnRlbnNpdHkgb2YgZXhwcHJlc3Npb24gYW5kIHRoZSBmcmFjdGlvbiBvZiBjZWxscyBleHByZXNzaW5nIGZvciBlYWNoIG9mIHlvdXIgZ2VuZXMgb2YgaW50ZXJlc3QuCmBgYHtyfQoKIyMjIyMjIyMjIyMjIyMjRmlndXJlMgoKClZsblBsb3QodGlzcywgZ2VuZXNfdG9fY2hlY2spCmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTh9CiMgVG8gY2hhbmdlIHRoZSB5LWF4aXMgdG8gc2hvdyByYXcgY291bnRzLCBhZGQgdXNlLnJhdyA9IFQuCkRvdFBsb3QodGlzcywgZ2VuZXNfdG9fY2hlY2ssIHBsb3QubGVnZW5kID0gVCkKYGBgCmBgYHtyfQpCdWlsZENsdXN0ZXJUcmVlKHRpc3MpCgpgYGAKCgoKQ2hlY2sgZXhwcmVzc2lvbiBvZiBnZW5lcyBvZiBpbnRlcnNldC4KCgpIb3cgYmlnIGFyZSB0aGUgY2x1c3RlcnM/CmBgYHtyfQp0YWJsZSh0aXNzQGlkZW50KQpgYGAKCgoKV2hpY2ggbWFya2VycyBpZGVudGlmeSBhIHNwZWNpZmljIGNsdXN0ZXI/CgpgYGB7cn0KY2x1c3QubWFya2VycyA8LSBGaW5kTWFya2VycyhvYmplY3QgPSB0aXNzLCBpZGVudC4xID0gMCwgb25seS5wb3MgPSBUUlVFLCBtaW4ucGN0ID0gMC4yNSwgdGhyZXNoLnVzZSA9IDAuMjUpCkRvdFBsb3QodGlzcywgZ2VuZXMucGxvdCA9IHJvd25hbWVzKGNsdXN0Lm1hcmtlcnMpWzE6MjBdLCBwbG90LmxlZ2VuZCA9IFQpCmBgYAoKCmBgYHtyfQpwcmludCh4ID0gaGVhZCh4PSBjbHVzdC5tYXJrZXJzLCBuID0gMTApKQpgYGAKCllvdSBjYW4gYWxzbyBjb21wdXRlIGFsbCBtYXJrZXJzIGZvciBhbGwgY2x1c3RlcnMgYXQgb25jZS4gVGhpcyBtYXkgdGFrZSBzb21lIHRpbWUuCgpgYGB7cn0KdGlzcy5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKG9iamVjdCA9IHRpc3MsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMjUsIHRocmVzaC51c2UgPSAwLjI1KQpgYGAKCkRpc3BsYXkgdGhlIHRvcCBtYXJrZXJzIHlvdSBjb21wdXRlZCBhYm92ZS4KYGBge3J9CnRpc3MubWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKDI1LCBhdmdfbG9nRkMpCmBgYAoKIyMgQXNzaWduaW5nIGNlbGwgdHlwZSBpZGVudGl0eSB0byBjbHVzdGVycwoKQXQgYSBjb2Fyc2UgbGV2ZWwsIHdlIGNhbiB1c2UgY2Fub25pY2FsIG1hcmtlcnMgdG8gbWF0Y2ggdGhlIHVuYmlhc2VkIGNsdXN0ZXJpbmcgdG8ga25vd24gY2VsbCB0eXBlczoKCgpgYGB7cn0KIyBzdGFzaCBjdXJyZW50IGNsdXN0ZXIgSURzCnRpc3MgPC0gU3Rhc2hJZGVudChvYmplY3QgPSB0aXNzLCBzYXZlLm5hbWUgPSAiY2x1c3Rlci5pZHMiKQoKIyBlbnVtZXJhdGUgY3VycmVudCBjbHVzdGVyIElEcyBhbmQgdGhlIGxhYmVscyBmb3IgdGhlbQpjbHVzdGVyLmlkcyA8LSBjKDAsIDEsIDIsIDMsIDQsIDUsIDYpCgpmcmVlX2Fubm90YXRpb24gPC0gYygKICAiQmxhZGRlciBtZXNlbmNoeW1hbCBjZWxsIiwgCiAgICJCbGFkZGVyIG1lc2VuY2h5bWFsIGNlbGwiLCAKICAgIkx1bWluYWwgYmxhZGRlciBlcGl0aGVsaWFsIGNlbGwiLCAKICAgIkx1bWluYWwgYmxhZGRlciBlcGl0aGVsaWFsIGNlbGwiLCAKICAgIkJhc2FsIGJsYWRkZXIgZXBpdGhlbGlhbCBjZWxsIiwKICAiQmxhZGRlciBtZXNlbmNoeW1hbCBjZWxsIiwKICAiQmFzYWwgYmxhZGRlciBlcGl0aGVsaWFsIGNlbGwiKQoKY2VsbF9vbnRvbG9neV9jbGFzcyA8LSBjKAogICJibGFkZGVyIGNlbGwiLCAKICAiYmxhZGRlciB1cm90aGVsaWFsIGNlbGwiLAogICAiYmxhZGRlciBjZWxsIiwgCiAgICAiYmxhZGRlciB1cm90aGVsaWFsIGNlbGwiLAogICAiYmxhZGRlciB1cm90aGVsaWFsIGNlbGwiLCAKICAiYmxhZGRlciBjZWxsIiwKICAgImJsYWRkZXIgdXJvdGhlbGlhbCBjZWxsIiwgCiAgICkKCmRhdGEuZnJhbWUoY2x1c3Rlci5pZHMsIAogICAgICAgICAgIGZyZWVfYW5ub3RhdGlvbiwgY2VsbF9vbnRvbG9neV9jbGFzcykKCiMgdGlzcyA9IHN0YXNoX2Fubm90YXRpb25zKHRpc3MsIGNsdXN0ZXIuaWRzLCBmcmVlX2Fubm90YXRpb24sIGNlbGxfb250b2xvZ3lfY2xhc3MpCgpUU05FUGxvdChvYmplY3QgPSB0aXNzLCBkby5sYWJlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjUsIGdyb3VwLmJ5PSdjZWxsX29udG9sb2d5X2NsYXNzJykKYGBgCgpgYGB7cn0KCiMjIyMjIyMjIyMjIyMjI0ZpZ3VyZTUKVFNORVBsb3Qob2JqZWN0ID0gdGlzcywgZG8ucmV0dXJuID0gVFJVRSwgZ3JvdXAuYnkgPSAibW91c2Uuc2V4IikKCmBgYAoKCiMjIENoZWNraW5nIGZvciBiYXRjaCBlZmZlY3RzCgoKQ29sb3IgYnkgbWV0YWRhdGEsIGxpa2UgcGxhdGUgYmFyY29kZSwgdG8gY2hlY2sgZm9yIGJhdGNoIGVmZmVjdHMuCmBgYHtyfQpUU05FUGxvdChvYmplY3QgPSB0aXNzLCBkby5yZXR1cm4gPSBUUlVFLCBncm91cC5ieSA9ICJwbGF0ZS5iYXJjb2RlIikKYGBgCgpQcmludCBhIHRhYmxlIHNob3dpbmcgdGhlIGNvdW50IG9mIGNlbGxzIGluIGVhY2ggaWRlbnRpdHkgY2F0ZWdvcnkgZnJvbSBlYWNoIHBsYXRlLgoKYGBge3J9CnRhYmxlKGFzLmNoYXJhY3Rlcih0aXNzQGlkZW50KSwgYXMuY2hhcmFjdGVyKHRpc3NAbWV0YS5kYXRhJHBsYXRlLmJhcmNvZGUpKQpgYGAKCmBgYHtyfQojIEdldCBtYXJrZXJzIGZvciBhIHBhcnRpY3VsYXIgY2x1c3Rlcgpmb3IgKGkgaW4gMDo2KSB7Y2x1c3Rlcm1hcmtlcnMgPSBmaWx0ZXIodGlzcy5tYXJrZXJzLCBjbHVzdGVyID09IGkpJGdlbmUKRG90UGxvdCh0aXNzLCBnZW5lcy5wbG90ID0gY2x1c3Rlcm1hcmtlcnNbMToxMF0sIHBsb3QubGVnZW5kID0gVCl9CmBgYAoKCiMgU2F2ZSB0aGUgUm9iamVjdCBmb3IgbGF0ZXIKV2hlbiB5b3Ugc2F2ZSB0aGUgYW5ub3RhdGVkIHRpc3N1ZSwgcGxlYXNlIGdpdmUgaXQgYSBuYW1lLgoKYGBge3J9CmZpbGVuYW1lID0gaGVyZSgnMDBfZGF0YV9pbmdlc3QnLCAnMDRfdGlzc3VlX3JvYmpfZ2VuZXJhdGVkJywgCgkJICBwYXN0ZTAoImZhY3MiLCB0aXNzdWVfb2ZfaW50ZXJlc3QsICJfc2V1cmF0X3Rpc3MuUm9iaiIpKQpwcmludChmaWxlbmFtZSkKc2F2ZSh0aXNzLCBmaWxlPWZpbGVuYW1lKQpgYGAKCmBgYHtyfQojIFRvIHJlbG9hZCBhIHNhdmVkIG9iamVjdAojIGZpbGVuYW1lID0gaGVyZSgnMDBfZGF0YV9pbmdlc3QnLCAnMDRfdGlzc3VlX3JvYmpfZ2VuZXJhdGVkJywgCiMgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCJmYWNzIiwgdGlzc3VlX29mX2ludGVyZXN0LCAiX3NldXJhdF90aXNzLlJvYmoiKSkKIyBsb2FkKGZpbGU9ZmlsZW5hbWUpCmBgYAoKCgojIEV4cG9ydCB0aGUgZmluYWwgbWV0YWRhdGEKClNvIHRoYXQgQmlvaHViIGNhbiBlYXNpbHkgY29tYmluZSBhbGwgeW91ciBjZWxsX29udG9sb2d5X2NsYXNzcywgcGxlYXNlIGV4cG9ydCB0aGVtIGFzIGEgc2ltcGxlIGNzdi4KCmBgYHtyfQpoZWFkKHRpc3NAbWV0YS5kYXRhKQpgYGAKCgpgYGB7cn0KZmlsZW5hbWUgPSBoZXJlKCcwMF9kYXRhX2luZ2VzdCcsICcwM190aXNzdWVfY2VsbF9vbnRvbG9neV9jbGFzc19jc3YnLCAKCQkgIHBhc3RlMCh0aXNzdWVfb2ZfaW50ZXJlc3QsICJfY2VsbF9vbnRvbG9neV9jbGFzcy5jc3YiKSkKCndyaXRlLmNzdih0aXNzQG1ldGEuZGF0YVssYygncGxhdGUuYmFyY29kZScsJ2NlbGxfb250b2xvZ3lfY2xhc3MnLCdjZWxsX29udG9sb2d5X2lkJyldLCBmaWxlPSJCbGFkZGVyX2NlbGxfb250b2xvZ3lfY2xhc3MuY3N2IikKYGBgCgoKIyMgQ2hlY2tpbmcgZm9yIGJhdGNoIGVmZmVjdHMKCkNvbG9yIGJ5IG1ldGFkYXRhLCBsaWtlIHBsYXRlIGJhcmNvZGUsIHRvIGNoZWNrIGZvciBiYXRjaCBlZmZlY3RzLgpgYGB7cn0KVFNORVBsb3Qob2JqZWN0ID0gc3VidGlzcywgZG8ucmV0dXJuID0gVFJVRSwgZ3JvdXAuYnkgPSAicGxhdGUuYmFyY29kZSIpCmBgYAoKUHJpbnQgYSB0YWJsZSBzaG93aW5nIHRoZSBjb3VudCBvZiBjZWxscyBpbiBlYWNoIGlkZW50aXR5IGNhdGVnb3J5IGZyb20gZWFjaCBwbGF0ZS4KCmBgYHtyfQp0YWJsZShhcy5jaGFyYWN0ZXIoc3VidGlzc0BpZGVudCksIGFzLmNoYXJhY3RlcihzdWJ0aXNzQG1ldGEuZGF0YSRwbGF0ZS5iYXJjb2RlKSkKYGBgCgoKIyBTYXZlIHRoZSBSb2JqZWN0IGZvciBsYXRlcgpXaGVuIHlvdSBzYXZlIHRoZSBhbm5vdGF0ZWQgdGlzc3VlLCBwbGVhc2UgZ2l2ZSBpdCBhIG5hbWUuCgpgYGB7cn0KZmlsZW5hbWUgPSBoZXJlKCcwMF9kYXRhX2luZ2VzdCcsICcwNF90aXNzdWVfcm9ial9nZW5lcmF0ZWQnLCAKCQkgIHBhc3RlMCgiZmFjcyIsIHRpc3N1ZV9vZl9pbnRlcmVzdCwgIl9zZXVyYXRfdGlzcy5Sb2JqIikpCnByaW50KGZpbGVuYW1lKQpzYXZlKHRpc3MsIGZpbGU9ZmlsZW5hbWUpCmBgYAoKYGBge3J9CiMgVG8gcmVsb2FkIGEgc2F2ZWQgb2JqZWN0CiMgZmlsZW5hbWUgPSBoZXJlKCcwMF9kYXRhX2luZ2VzdCcsICcwNF90aXNzdWVfcm9ial9nZW5lcmF0ZWQnLCAKIyAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoImZhY3MiLCB0aXNzdWVfb2ZfaW50ZXJlc3QsICJfc2V1cmF0X3Rpc3MuUm9iaiIpKQojIGxvYWQoZmlsZT1maWxlbmFtZSkKYGBgCgoKCiMgRXhwb3J0IHRoZSBmaW5hbCBtZXRhZGF0YQoKU28gdGhhdCBCaW9odWIgY2FuIGVhc2lseSBjb21iaW5lIGFsbCB5b3VyIGNlbGxfb250b2xvZ3lfY2xhc3NzLCBwbGVhc2UgZXhwb3J0IHRoZW0gYXMgYSBzaW1wbGUgY3N2LgoKYGBge3J9CmhlYWQodGlzc0BtZXRhLmRhdGEpCmBgYAoKCmBgYHtyfQpmaWxlbmFtZSA9IGhlcmUoJzAwX2RhdGFfaW5nZXN0JywgJzAzX3Rpc3N1ZV9hbm5vdGF0aW9uX2NzdicsIAogICAgICAgICAgICAgICAgICAgICBwYXN0ZTAodGlzc3VlX29mX2ludGVyZXN0LCAiX2ZhY3NfYW5ub3RhdGlvbi5jc3YiKSkKd3JpdGUuY3N2KEZldGNoRGF0YSh0aXNzLCBjKCdwbGF0ZS5iYXJjb2RlJywnY2VsbF9vbnRvbG9neV9jbGFzcycsJ2NlbGxfb250b2xvZ3lfaWQnLCAnZnJlZV9hbm5vdGF0aW9uJywgJ3RTTkVfMScsICd0U05FXzInKSksIGZpbGU9ZmlsZW5hbWUpCmBgYAo=